/**
 * 
 */
package com.dfhc.client.service;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;

import com.alibaba.fastjson.JSON;
import com.dfhc.ISystemConstant;
import com.dfhc.PjException;
import com.dfhc.client.SequenceException;
import com.dfhc.client.vo.RequestNextValueVo;
import com.dfhc.client.vo.ResponseNextValueVo;
import com.dfhc.util.ConvertHelper;
import com.dfhc.util.StringHelper;

/**
 * 序列客户端服务
 * 
 * @author longsebo
 */
public class SequenceClientService {
	// 序列缓存
	private Map<String, List<String>> sequenceCache = null;
	private static SequenceClientService sequenceClientService;

	private SequenceClientService() {
		sequenceCache = new HashMap<String, List<String>>();
	}

	/**
	 * 获取单例
	 * 
	 * @return
	 */
	public synchronized static SequenceClientService getInstance() {
		if (sequenceClientService == null) {
			sequenceClientService = new SequenceClientService();
		}
		return sequenceClientService;
	}

	/**
	 * 获取下一批序列值
	 * 
	 * @param url
	 *            服务器url
	 * @param size
	 *            序列值个数
	 * @param domainName
	 *            域名
	 * @param sequenceName
	 *            序列名称
	 * @param args
	 *            动态参数
	 * @return
	 * @throws SequenceException
	 */
	public String[] getNextSequenceValue(String url, int size,
			String domainName, String sequenceName, Object... args)
			throws SequenceException {
		String[] seqNums = null;
		boolean isNeedSequence = false;
		List<String> sequences = null;
		int batchNum = 1000;
		String key;
		key = domainName + "." + sequenceName;
		// 优化从缓存获取，如果序列个数不足或者缓存里没有，则从一次取1000条,如果seqNum超过1000条，则取seqNum
		synchronized (sequenceCache) {
			sequences = sequenceCache.get(key);
			if (sequences == null) {
				sequences = new ArrayList<String>();
				sequenceCache.put(key, sequences);
				isNeedSequence = true;
			} else {
				synchronized (sequences) {
					if (sequences.size() < size) {
						isNeedSequence = true;
					}
				}

			}
		}

		if (!isNeedSequence) {
			synchronized (sequences) {
				seqNums = new String[size];
				for (int i = 0; i < size; i++) {
					seqNums[i] = sequences.remove(0);
				}
				return seqNums;
			}
		} else {
			RequestNextValueVo requestVo = new RequestNextValueVo();
			requestVo.setDomainName(domainName);
			if (batchNum < size) {
				batchNum = size;
			}
			requestVo.setNum(batchNum);
			requestVo.setSequenceName(sequenceName);
			requestVo.setParameters(args);
			// 将requestVo转换为json串
			String requestVoJson = JSON.toJSONString(requestVo);
			// 创建httppost
			HttpPost httppost = new HttpPost(url);
			// 创建参数队列
			List<NameValuePair> formparams = new ArrayList<NameValuePair>();
			formparams.add(new BasicNameValuePair(
					ISystemConstant.PARAM_REQUESTJSON, requestVoJson));
			CloseableHttpClient httpclient = null;
			InputStream in = null;
			UrlEncodedFormEntity uefEntity;
			try {
				httpclient = HttpClients.createDefault();
				uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
				httppost.setEntity(uefEntity);
				System.out.println("executing request " + httppost.getURI());
				HttpResponse response = httpclient.execute(httppost);
				HttpEntity entity = response.getEntity();
				in = entity.getContent();

				// 获取应答的Json串
				String responseJson;
				responseJson = ConvertHelper.inputStream2String(in);
				// 将json串转换为
				ResponseNextValueVo responseVo;
				responseVo = JSON.parseObject(responseJson,
						ResponseNextValueVo.class);
				if (ISystemConstant.Result.SUCCESS.code().equals(
						responseVo.getErrorCode())) {
					List<String> tempVaues = new ArrayList<String>();
					int curVal = responseVo.getMaxValue();
					int startVal = responseVo.getMinValue();
					// 格式当期值为字符串
					Integer valLen;
					valLen = responseVo.getSenderVo().getSequenceLen();

					// 获取序列格式化规则
					String sequenRule = responseVo.getSenderVo()
							.getSequenceRule();
					String curValFmt = "%0" + ConvertHelper.toString(valLen)
							+ "d";
					String fmtCurVal;
					for (int i = startVal; i <= curVal; i++) {
						String strCurVal = String.format(curValFmt, i);
						// 将规则中的%value替换为strCurVal,然后再格式化
						sequenRule = StringHelper.replaceAll(
								responseVo.getSenderVo().getSequenceRule(),
								ISystemConstant.FMT_SEQ_VALUE, strCurVal)
								.toString();
						fmtCurVal = String.format(sequenRule, args);
						tempVaues.add(fmtCurVal);
					}
					// 同步列表,加入队列，然后从头取旧的
					seqNums = new String[size];
					synchronized (sequences) {
						sequences.addAll(tempVaues);
						tempVaues.clear();
						for (int i = 0; i < size; i++) {
							seqNums[i] = sequences.remove(0);
						}
					}
					return seqNums;
				} else {
					throw new PjException(responseVo.getErrorMsg());
				}
			} catch (Exception e) {
				throw new SequenceException(e);
			} finally {
				if (in != null) {
					try {
						in.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				if (httpclient != null) {
					try {
						httpclient.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	/**
	 * 获取下一个序列值
	 * 
	 * @param url
	 *            服务器url
	 * @param size
	 *            序列值个数
	 * @param domainName
	 *            域名
	 * @param sequenceName
	 *            序列名称
	 * @param args
	 *            动态参数
	 * @return
	 * @throws SequenceException
	 */
	public String getNextSequenceValue(String url, String domainName,
			String sequenceName, Object... args) throws SequenceException {
		RequestNextValueVo requestVo = new RequestNextValueVo();
		requestVo.setDomainName(domainName);

		requestVo.setNum(1);
		requestVo.setSequenceName(sequenceName);
		requestVo.setParameters(args);
		// 将requestVo转换为json串
		String requestVoJson = JSON.toJSONString(requestVo);
		// 创建httppost
		HttpPost httppost = new HttpPost(url);
		// 创建参数队列
		List<NameValuePair> formparams = new ArrayList<NameValuePair>();
		formparams.add(new BasicNameValuePair(
				ISystemConstant.PARAM_REQUESTJSON, requestVoJson));
		CloseableHttpClient httpclient = null;
		InputStream in = null;
		UrlEncodedFormEntity uefEntity;
		try {
			httpclient = HttpClients.createDefault();
			uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
			httppost.setEntity(uefEntity);
			System.out.println("executing request " + httppost.getURI());
			HttpResponse response = httpclient.execute(httppost);
			HttpEntity entity = response.getEntity();
			in = entity.getContent();

			// 获取应答的Json串
			String responseJson;
			responseJson = ConvertHelper.inputStream2String(in);
			// 将json串转换为
			ResponseNextValueVo responseVo;
			responseVo = JSON.parseObject(responseJson,
					ResponseNextValueVo.class);
			if (ISystemConstant.Result.SUCCESS.code().equals(
					responseVo.getErrorCode())) {
				int curVal = responseVo.getMaxValue();
				int startVal = responseVo.getMinValue();
				// 格式当期值为字符串
				Integer valLen;
				valLen = responseVo.getSenderVo().getSequenceLen();

				// 获取序列格式化规则
				String sequenRule = responseVo.getSenderVo().getSequenceRule();
				String curValFmt = "%0" + ConvertHelper.toString(valLen) + "d";
				String fmtCurVal = null;
				for (int i = startVal; i <= curVal;) {
					String strCurVal = String.format(curValFmt, i);
					// 将规则中的%value替换为strCurVal,然后再格式化
					sequenRule = StringHelper.replaceAll(
							responseVo.getSenderVo().getSequenceRule(),
							ISystemConstant.FMT_SEQ_VALUE, strCurVal)
							.toString();
					fmtCurVal = String.format(sequenRule, args);
					return fmtCurVal;
				}
				throw new PjException("没格式化值，返回的开始值：" + startVal + ",返回的结束值:"
						+ curVal);

			} else {
				throw new PjException(responseVo.getErrorMsg());
			}
		} catch (Exception e) {
			throw new SequenceException(e);
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (httpclient != null) {
				try {
					httpclient.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}
}
